<?php

/* ========================================================================= */
/* This file is part of the HypnoPHP Framework Library                       */
/* Copyright (c) 2009-2010, Radu Buzea                                       */
/* ========================================================================= */

/**
* @author Radu Buzea
* @copyright Copyright (c) 2009-2010, Radu Buzea (www.hypnosis.ro)
* @license GNU Lesser General Public License (www.gnu.org/copyleft/lesser.html)
* @package HypnoPHP
* @category Core
* @version 1.0.3
*/

defined('HYPNOPHP_APPLICATION') or
die("Cannot use <i>" . basename(__FILE__) . "</i> outside HypnoPHP Application");

// ============================================================================
// Final class: HResponse
// ============================================================================

final class HResponse extends HBaseObject
{
	protected $__content_type = 'text/html';
	protected $__enable_gzip_compression = false;
	protected $__gzip_compression_threshold = 0;

	# ###########################################################################

	/**
	* Get the content type - property getter method
	*
	*	@return string
	*/
	public function __get_content_type()
	{
		return $this->__content_type;
	}

	# ###########################################################################

	/**
	* Set the content type - property setter method
	*
	* @param string $value
	*	@return void
	*/
	public function __set_content_type($value = 'text/html')
	{
		if (trim($value) == '') { $value = 'text/html'; }
		$this->__content_type = strtolower(trim($value));
	}

	# ###########################################################################

	/**
	* Get the enable gzip compression status - property getter method
	*
	*	@return bool
	*/
	public function __get_enable_gzip_compression()
	{
		return $this->__enable_gzip_compression;
	}

	# ###########################################################################

	/**
	* Set the enable gzip compression status - property setter method
	*
	* @param bool $value
	*	@return void
	*/
	public function __set_enable_gzip_compression($value = false)
	{
		$this->__enable_gzip_compression = boolval($value);
	}

	# ###########################################################################

	/**
	* Get the gzip compression threshold - property getter method
	*
	*	@return integer
	*/
	public function __get_gzip_compression_threshold()
	{
		return $this->__gzip_compression_threshold;
	}

	# ###########################################################################

	/**
	* Set the gzip compression threshold - property setter method
	*
	* @param integer $value
	*	@return void
	*/
	public function __gzip_compression_threshold($value = 0)
	{
		$this->__gzip_compression_threshold = intval($value);
	}

	# ###########################################################################

	/**
	* Initialise the response object
	*
	* @return void
	*/
	public static function init_response()
	{
		$response = self::getInstance();
		$response->headers = array();
	}

	# ###########################################################################

	/**
	* Send a HTTP redirect header
	*
	* @param string $uri
	* @return void
	*/
	public static function redirect($uri = '')
	{
		$response = self::getInstance();
		if (headers_sent()) {
			$response->addError("Cannot redirect to <i>{$uri}</i> because the HTTP headers have already been sent",
				E_USER_WARNING);
			return false;
		}
		header("Location:{$uri}");
		exit;
	}

	# ###########################################################################

	/**
	* Set a raw HTTP header response
	*
	* @param string or array $param1
	* @param string $param2
	*/
	public static function set_header($param1, $param2 = null)
	{
		$vars = null;
		if (is_array($param1)) {
			if (is_array($param2)) { $vars = array_combine($param1, $param2); }
			else { $vars = $param1; }
		} else if (is_string($param1)) {
			if ($param2 == null) {
				$vars = array(1 => $param2);
			} else {
				$vars = array($param1 => $param2);
			}
		}
		if ($vars == null) { return false; }
		$headers = array();
		$response = self::getInstance();
		foreach ($vars as $var_name => $var_value) {
			if (is_int($var_name) && $var_name == 1) {
				$headers[] = $var_value;
			} else {
				if (strtolower($var_name) == 'content-type') {
					$response->content_type = $var_value;
				}
				$headers[$var_name] = $var_value;
			}
		}
		$response->headers = $headers;
	}

	# ###########################################################################

	/**
	* Get the content type (static method)
	*
	* @return string
	*/
	public static function get_content_type()
	{
		$response = self::getInstance();
		return $response->content_type;
	}

	# ###########################################################################

	/**
	* Set the content type (static method)
	*
	* @param string $value
	* @return void
	*/
	public static function set_content_type($value = null)
	{
		$response = self::getInstance();
		$headers = $response->headers;
		if (!is_string($value) || trim($value) == '') {
			$headers['Content-type'] = 'text/html';
			$response->content_type = 'text/html';
		} else {
			$value = trim($value);
			$headers['Content-type'] = $value;
			$response->content_type = $value;
		}
		$response->headers = $headers;
	}

	# ###########################################################################

	/**
	* Check if the output content type is a text
	*
	* @return bool
	*/
	public static function is_text_output()
	{
		$response = self::getInstance();
		return (substr(strtolower($response->content_type), 0, 4) == 'text');
	}

	# ###########################################################################

	/**
	* Send the HTTP headers
	*
	* @return bool
	*/
	public static function send_headers()
	{
		$response = self::getInstance();
		if (is_array($response->headers) && count($response->headers) > 0) {
			$headers = $response->headers;
			if (headers_sent()) {
				$response->addError("HTTP headers have already been sent", E_USER_WARNING);
				return false;
			}
			foreach ($headers as $header_param => $header_value) {
				if (is_int($header_param)) { header($header_value); }
				else { header(trim($header_param) . ': ' . $header_value); }
			}
		}
		return true;
	}

	# ###########################################################################

	/**
	* Enables the gzip comperssion and sets the compression threshold
	*
	* @param int $threshold The compression threshold (0 to disable the gzip comperssion)
	* @return bool
	*/
	public static function enable_gzip_compression($threshold = 30100)
	{
		if (is_bool($threshold)) { $threshold = $threshold ? 30100 : 0; }
		elseif (!is_int($threshold)) { $threshold = intval($threshold); }
		$response = self::getInstance();
		$response->enable_gzip_compression = ($threshold > 0);
		$response->gzip_compression_threshold = $threshold;
		return $response->enable_gzip_compression;
	}

	# ###########################################################################

	/**
	* Check if zlib extension is loaded and if the client browser accepts gzip encoding
	*
	* @return bool
	*/
	public static function check_gzip_compression()
	{
		$output_compression = @ini_get("zlib.output_compression");
		return (!$output_compression && extension_loaded("zlib") &&
			strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') !== false);
	}

	# ###########################################################################

	/**
	* Set the HTTP authentication header
	*
	* @param string $realm The authentication basic real
	* @return void
	*/
	public static function http_authentication($realm = '')
	{
		$realm = trim($realm);
		if ($realm == '') { $realm = 'HypnoPHP HTTP Authentication'; }
		header('WWW-Authenticate: Basic realm="' . $realm . '"');
		header('HTTP/1.0 401 Unauthorized');
		self::set_header('WWW-Authenticate', 'Basic realm="' . $realm . '"');
		self::set_header(null, 'HTTP/1.0 401 Unauthorized');

	}

	# ###########################################################################

	/**
	* Set the HTTP authentication header
	*
	* @param string $data The output content
	* @param array $headers (optional, default null) A set of additional header params
	* @return string
	*/
	public static function output($data = '', $headers = null)
	{
		if (is_array($headers) && count($headers) > 0) {
			foreach ($headers as $header_param => $header_value) {
				self::set_header($header_param, $header_value);
			}
		}

		HSession::save_session();
		HCookie::saveCookies();

		self::send_headers();
		$compress = false;
		$response = self::getInstance();
		if ($response->enable_gzip_compression && self::check_gzip_compression()) {
			if (strlen($data) > $response->gzip_compression_threshold) {
				$compress = true;
				ob_start();
				ob_start('ob_gzhandler');
			} else {
				header('Content-length: ' . strlen($data));
			}
		}
		print($data);
		if ($compress) {
			ob_end_flush();
			header('Content-length: ' . ob_get_length());
			ob_end_flush();
		}
	}

	# ###########################################################################

	/**
	* Get the response object instance (singleton)
	*
	* @return HResponse
	*/
	public static function getInstance()
	{
		return self::singleton(__CLASS__);
	}

	# ###########################################################################

}
